/**
 * A priority queue is constructed in the class, and stores all matching results
 * in a decresing order of the similarities.
 */
package qy.course.cse494.ir;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import qy.course.cse494.util.Pair;

/**
 * @author qyan
 *
 */
public class DocumentHits
{
	List<Pair<Integer, Double>> _result_pair_list = new LinkedList<Pair<Integer,Double>>();
	Map<Integer, Pair<Integer, Double>> _doc_pair_index = new TreeMap<Integer, Pair<Integer, Double>>();
	int _limit_size = 10;
		
	/**
	 * Constructor
	 * @param _limit_size
	 */
	public DocumentHits(int limit_size)
	{
		_limit_size = limit_size;
	}

	/**
	 * Default constructor
	 */
	public DocumentHits()
	{
		_limit_size = -1;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return _result_pair_list.toString();
	}

	public void set_hits_size(int length)
	{
		_limit_size = length; 
	}
	
	/**
	 * Binary search is exploited to find the right position 
	 * of the new element. 
	 * @param weight
	 * @return the position of the new element
	 */
	private int _bin_locate_pos(double weight)
	{
		int mid = 0;
		int low = 0;
		int high = _result_pair_list.size() - 1;
		//
		while(low <= high)
		{
			mid = (low+high)/2;
			if(_result_pair_list.get(mid).second() == weight)
				return mid+1;
			if(_result_pair_list.get(mid).second() < weight)
			{
				high = mid - 1;
			}else
			{
				low = mid + 1;
			}
		}
		return low;
	}
	
	public void clear()
	{
		_result_pair_list.clear();
	}
	
	public void add_hit(int doc_id, double weight)
	{
		if(_doc_pair_index.containsKey(doc_id))
		{
			if(_doc_pair_index.get(doc_id).second() > weight)
			{
				return;
			}else
			{
				_result_pair_list.remove(_doc_pair_index.get(doc_id));
			}
		}
		//
		Pair<Integer, Double> val = new Pair<Integer, Double>(doc_id, weight);
		_result_pair_list.add(_bin_locate_pos(weight), val);
		_doc_pair_index.put(doc_id, val);
		
		if(_limit_size > 0 && _result_pair_list.size() > _limit_size)
		{
			int size_of_results = _result_pair_list.size();
			_doc_pair_index.remove(_result_pair_list.get(size_of_results-1).first());
			_result_pair_list.remove(size_of_results-1);			
		}
	}
	
	/**
	 * It only reflects the size of the current results.
	 * @return
	 */
	public int size()
	{
		return _result_pair_list.size();
	}
	
	public int length()
	{
		return _result_pair_list.size();
	}
	
	public Pair<Integer, Double> get_result_ranked_at(int i)
	{
		if(i >= _result_pair_list.size())
		{
			System.err.println("The result :" + i +" doesn't exist!!!");
		}
		return _result_pair_list.get(i);
	}
	
	public int get_doc_id_ranked_at(int i)
	{
		return get_result_ranked_at(i).first();
	}
	
	public double get_weight_ranked_at(int i)
	{
		return get_result_ranked_at(i).second();
	}
	
	public Set<Integer> get_hit_page_set()
	{
		return _doc_pair_index.keySet();
	}
	
}
